package org.unidata.mdm.rest.v1.meta.service.groups;

import java.util.Objects;
import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import org.springframework.beans.factory.annotation.Autowired;
import org.unidata.mdm.core.service.MetaModelService;
import org.unidata.mdm.meta.context.GetDataModelContext;
import org.unidata.mdm.meta.context.UpsertDataModelContext;
import org.unidata.mdm.meta.dto.GetEntitiesGroupsDTO;
import org.unidata.mdm.meta.dto.GetModelDTO;
import org.unidata.mdm.rest.v1.meta.converter.entities.EntitiesGroupConverter;
import org.unidata.mdm.rest.v1.meta.ro.groups.FilledEntityGroupMappingRO;
import org.unidata.mdm.rest.v1.meta.ro.groups.GetFiledGroupsResultRO;
import org.unidata.mdm.rest.v1.meta.ro.groups.GetFlatGroupsResultRO;
import org.unidata.mdm.rest.v1.meta.ro.groups.UpsertEntityGroupRequestRO;
import org.unidata.mdm.rest.v1.meta.ro.groups.UpsertEntityGroupResultRO;
import org.unidata.mdm.rest.v1.meta.service.AbstractMetaModelRestService;

/**
 * Group rest service
 *
 * @author Alexandr Serov
 * @since 24.11.2020
 **/
@Path(EntitiesGroupRestService.SERVICE_PATH)
@Consumes({"application/json"})
@Produces({"application/json"})
public class EntitiesGroupRestService extends AbstractMetaModelRestService {

    /**
     * This service path.
     */
    public static final String SERVICE_PATH = "entities-group";
    public static final String SERVICE_TAG = "entities-group";
    /**
     * The metamodel service.
     */
    @Autowired
    private MetaModelService metaModelService;

    /**
     * Load and return list of all entities group
     *
     * @return list of source systems. {@see FlatGroupMapping}.
     */
    @Path("filled")
    @GET
    @Operation(
        description = "Return all entity groups, starting from the root.",
        method = HttpMethod.GET,
        tags = SERVICE_TAG
    )
    public GetFiledGroupsResultRO findFiledGroups(
        @Parameter(description = "Draft id for draft version.", in = ParameterIn.QUERY)
        @QueryParam("draftId") @DefaultValue("0") Long draftId) {

        GetFiledGroupsResultRO result = new GetFiledGroupsResultRO();
        GetEntitiesGroupsDTO groups = groupsByDraftId(draftId);
        if (groups != null) {
            result.setFiledEntityGroups(EntitiesGroupConverter.extractFilledNodes(groups));
        }
        return result;
    }

    /**
     * Load and return list of all entities group
     *
     * @return list of source systems. {@see FlatGroupMapping}.
     */
    @Path("flat")
    @GET
    @Operation(
        description = "Return all entity groups, starting from the root.",
        method = HttpMethod.GET,
        tags = SERVICE_TAG
    )
    public GetFlatGroupsResultRO findFlatGroups(
        @Parameter(description = "Draft id for draft version.", in = ParameterIn.QUERY)
        @QueryParam("draftId") @DefaultValue("0") Long draftId) {

        GetFlatGroupsResultRO result = new GetFlatGroupsResultRO();
        GetEntitiesGroupsDTO groups = groupsByDraftId(draftId);
        if (groups != null) {
            result.setFlatEntityGroups(EntitiesGroupConverter.extractFlatNodes(groups));
        }
        return result;
    }

    /**
     * Create or update entities group.
     *
     * @return 200 Ok
     */
    @POST
    @Operation(
        description = "Upsert an entities group.",
        method = HttpMethod.POST,
        tags = SERVICE_TAG)
    public UpsertEntityGroupResultRO update(UpsertEntityGroupRequestRO req) {
        Objects.requireNonNull(req, "Request can't be null");
        FilledEntityGroupMappingRO ro = notNull("group", req.getGroup());
        UpsertEntityGroupResultRO result = new UpsertEntityGroupResultRO();
        metaModelService.upsert(UpsertDataModelContext.builder()
            .entitiesGroupsUpdate(EntitiesGroupConverter.from(ro))
            .draftId(resolveDraftId(req.getDraftId()))
            .build());
        return result;
    }

    private GetEntitiesGroupsDTO groupsByDraftId(Long draftId) {
        GetModelDTO result = metaModelService.get(GetDataModelContext.builder()
            .draftId(resolveDraftId(draftId))
            .allEntityGroups(true)
            .build());
        GetEntitiesGroupsDTO groups = null;
        if (result != null) {
            groups = result.getEntityGroups();
        }
        return groups;
    }

}
